package io.github.hayeka.excel.context;

import io.github.hayeka.excel.anno.ExcelColumn;
import io.github.hayeka.excel.anno.ExcelEntity;
import io.github.hayeka.excel.domain.SheetInformation;
import io.github.hayeka.excel.helper.ClassHelper;
import io.github.hayeka.excel.util.LogUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.util.*;

/**
 * program:
 * description: 信息存储类
 * author:
 * create: 2021/8/27
 **/

@SuppressWarnings("all")
public class ExcelApplicationContext {

    private static final Logger logger = LoggerFactory.getLogger(ExcelApplicationContext.class);
    private static Map<Class, SheetInformation> map = new HashMap<>();
    private static boolean initFlag = false;
    //持有所有@ExcelEntity的类
    private static Set<Class<?>> classesInPackage = null;
    private static Set<Class<?>> classesWithAnno = new HashSet<>();
    private static float keyInterval = 0.0001f;


    /**
     * @param packageName
     */
    public static void initUserSetting(String packageName) {
        if (initFlag) {
            LogUtils.out(logger, "ExcelApplicationContext不需要再初始化");
            return;
        }
        logBegin();
        classesInPackage = ClassHelper.getClassesByPackageName(packageName);
        LogUtils.out(logger, "包:" + packageName + "==>" + "共扫描到" + classesInPackage.size() + "个类");
        filterWithAnno();
        convertClassToSheetInformation();
        initFlag = true;
        logEnd();
    }

    private static void convertClassToSheetInformation() {
        if (classesWithAnno == null || classesWithAnno.size() == 0) {
            return;
        }
        SheetInformation sheetInformation = null;
        //必带有@ExcelEntity注解的类
        for (Class<?> clazz : classesWithAnno) {
            sheetInformation = new SheetInformation();
            fillSheetName(sheetInformation, clazz);
            fillTitleAndFieldList(sheetInformation, clazz);
            map.put(clazz, sheetInformation);
        }
    }

    private static void fillTitleAndFieldList(SheetInformation sheetInformation, Class<?> clazz) {
        TreeMap<Float, String> titleTreeMap = new TreeMap<>();
        TreeMap<Float, String> fieldTreeMap = new TreeMap<>();
        ExcelColumn annotation = null;
        for (Field field : clazz.getDeclaredFields()) {
            annotation = field.getAnnotation(ExcelColumn.class);
            if (annotation == null) {
                continue;
            }
            if (annotation.show()) {
                float key = Integer.valueOf(annotation.sort()).floatValue();
                checkAndPut(titleTreeMap, key, annotation.columnName());
                checkAndPut(fieldTreeMap, key, field.getName());
            }
        }
        sheetInformation.setFieldNameList(new ArrayList<>(fieldTreeMap.values()));
        sheetInformation.setTitleNameList(new ArrayList<>(titleTreeMap.values()));
    }

    private static void checkAndPut(TreeMap<Float, String> treeMap, float key, String value) {
        if (treeMap.containsKey(key)) {
            checkAndPut(treeMap, key + keyInterval, value);
        } else {
            treeMap.put(key, value);
        }
    }

    private static void fillSheetName(SheetInformation sheetInformation, Class<?> clazz) {
        sheetInformation.setSheetName(clazz.getAnnotation(ExcelEntity.class).sheetName());
    }

    /**
     * @param classesInPackage
     */
    private static void filterWithAnno() {
        if (classesInPackage == null || classesInPackage.size() == 0) {
            return;
        }
        for (Class<?> clazz : classesInPackage) {
            ExcelEntity annotation = clazz.getAnnotation(ExcelEntity.class);
            if (annotation != null) {
                classesWithAnno.add(clazz);
            }
        }
        LogUtils.out(logger, "共扫描到" + classesWithAnno.size() + "个带有@ExcelEntity类");
    }

    private static void logEnd() {
        LogUtils.out(logger, "====================ExcelApplicationContext init end==============================");
    }

    private static void logBegin() {
        LogUtils.out(logger, "====================ExcelApplicationContext init begin============================");
    }


    public static Map<Class, SheetInformation> getMap() {
        return map;
    }
}
